package com.appBase.tools;

import android.webkit.MimeTypeMap;

import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.handler.stream.ChunkedNioFile;

import java.io.*;
import java.util.Locale;

import static io.netty.handler.codec.http.HttpResponseStatus.*;

public class FileServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    private final String basePath;

    public FileServerHandler(String basePath) {
        this.basePath = basePath;
    }

    protected void channelRead0(ChannelHandlerContext channelHandlerContext, FullHttpRequest request) throws Exception {
        //request.retain();
        HttpResponse response = null;
        RandomAccessFile randomAccessFile = null;
        try{
            // 状态为1xx的话，继续请求
            if (HttpHeaders.is100ContinueExpected(request)) {
                send100Continue(channelHandlerContext);
            }
            String uri = request.uri();
            System.out.println("path:" + uri);
            int ind = uri.indexOf("?");
            if (ind >= 0) {
                uri = uri.substring(0, ind);
            }

            // hello/a.js
            int index = uri.indexOf("/") + 1;
            if(index == 0){
               DonkeyHttpUtil.writeResponse(request, OK, channelHandlerContext);
               return;
            }
            String filename = uri.substring(index);
            String fullPath = this.basePath + "/"+filename;
            File file = new File(fullPath);
            try {
                randomAccessFile = new RandomAccessFile(file, "r");
            } catch (FileNotFoundException e) {
                DonkeyHttpUtil.writeResponse(request, NOT_FOUND, channelHandlerContext);
                e.printStackTrace();
                return;
            }

            if(!file.exists() || file.isHidden()){
                DonkeyHttpUtil.writeResponse(request, NOT_FOUND, channelHandlerContext);
                return;
            }
            long fileLength = randomAccessFile.length();
            response = new DefaultHttpResponse(request.protocolVersion(), HttpResponseStatus.OK);

            setContentType(response, file);
            boolean keepAlive =  HttpUtil.isKeepAlive(request);
            if (keepAlive) {
                response.headers().set(HttpHeaderNames.CONTENT_LENGTH, fileLength);
                response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
            }
            channelHandlerContext.write(response);


            ChannelFuture sendFileFuture = channelHandlerContext.write(new ChunkedNioFile(randomAccessFile.getChannel()), channelHandlerContext.newProgressivePromise());
            // 写入文件尾部
            sendFileFuture.addListener(new ChannelProgressiveFutureListener() {
                @Override
                public void operationProgressed(ChannelProgressiveFuture future,
                                                long progress, long total) {
//                    if (total < 0) { // total unknown
//                        System.out.println("Transfer progress: " + progress);
//                    } else {
//                        System.out.println("Transfer progress: " + progress + " / "
//                                + total);
//                    }
                }

                @Override
                public void operationComplete(ChannelProgressiveFuture future)
                        throws Exception {
//                    System.out.println("Transfer complete.");
                }


            });
            ChannelFuture lastContentFuture =  channelHandlerContext.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
            if (!keepAlive) {
                lastContentFuture.addListener(ChannelFutureListener.CLOSE);
            }
        }finally {
//            if(randomAccessFile != null){
//                try {
//                    randomAccessFile.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
        }
    }

    private void setContentType(HttpResponse response, File file){
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, getContentTypeHeader(file));
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }

    private static void send100Continue(ChannelHandlerContext ctx) {
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);
        ctx.writeAndFlush(response);
    }


    private String getContentTypeHeader(File file) {

        //HttpHeaders headers = new DefaultHttpHeaders();
        String contentType = getMimeType(file);
        if (contentType.equals("text/plain")) {
            //由于文本在浏览器中会显示乱码，此处指定为utf-8编码
            contentType = "text/plain;charset=utf-8";
        }
        //headers.set(HttpHeaderNames.CONTENT_TYPE, contentType);
        return contentType;
    }

    private String getSuffix(File file) {
        if (file == null || !file.exists() || file.isDirectory()) {
            return null;
        }
        String fileName = file.getName();
        if (fileName.equals("") || fileName.endsWith(".")) {
            return null;
        }
        int index = fileName.lastIndexOf(".");
        if (index != -1) {
            return fileName.substring(index + 1).toLowerCase(Locale.US);
        } else {
            return null;
        }
    }

    public String getMimeType(File file){
        String suffix = getSuffix(file);
        if (suffix == null) {
            return "file/*";
        }
        if (suffix.equals("js")) {
            return "application/javascript";
        }
        if (suffix.equals("ttf")) {
            return "application/octet-stream";
        }

        if (suffix.equals("woff2")) {
            System.out.println("suffix:" + suffix);
            return "application/octet-stream";
        }

        String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(suffix);
        if (type != null || !type.isEmpty()) {
            return type;
        }
        return "file/*";
    }

}
